#include "d3d_video_renderer.hpp"
#include "p2pms_log.hpp"

#include <cassert>
#include <d3dcompiler.h>

#include "third_party/libyuv/include/libyuv/convert_argb.h"


// 顶点着色器代码 (HLSL)
const char* vs_code = R"(
	struct VSInput {
		float3 position : POSITION;
		float2 texcoord : TEXCOORD;
	};
	struct PSInput {
		float4 position : SV_POSITION;
		float2 texcoord : TEXCOORD;
	};
	PSInput VSMain(VSInput input) {
		PSInput output;
		output.position = float4(input.position, 1.0);
		output.texcoord = input.texcoord;
		return output;
	}
)";

// 像素着色器代码 (HLSL)
const char* ps_code = R"(
	Texture2D tex : register(t0);
	SamplerState samp : register(s0);
	float4 PSMain(float4 position : SV_POSITION, float2 texcoord : TEXCOORD) : SV_TARGET {
		return tex.Sample(samp, texcoord);
	}
)";

namespace p2pms
{

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
D3DVideoRenderer::D3DVideoRenderer(const MediaInfo& media, IMainThreadExecutor* executor)
{
	LOG_INF("Constructing D3DVideoRenderer");

	assert(executor);
	m_media_info = media;
	m_executor = executor;
	m_bgra_buffer.clear();
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
D3DVideoRenderer::~D3DVideoRenderer()
{
	LOG_INF("Destroying D3DVideoRenderer");

	Cleanup();
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
bool D3DVideoRenderer::SetRenderWindow(void* window_handle)
{
	std::lock_guard<std::mutex> lock(m_mutex);

	LOG_INF("Setting render window: {}", window_handle);

	if (m_hwnd == static_cast<HWND>(window_handle)) {
		LOG_INF("Render window already set to the same handle");
		return true;
	}

	// 如果句柄为空，停止渲染并清理资源
	if (!window_handle && m_hwnd) {
		LOG_INF("Setting render window to nullptr, stopping rendering");
		Stop();
		Cleanup();
		m_hwnd = nullptr;
		return true;
	}

	// 获取窗口客户区实际大小
	RECT rc = {0};
	if (!GetClientRect(static_cast<HWND>(window_handle), &rc)) {
		LOG_ERR("GetClientRect failed");
		return false;
	}

	int width = rc.right - rc.left;
	int height = rc.bottom - rc.top;
	if (width <= 0 || height <= 0) {
		LOG_ERR("Invalid window size: {}x{}", width, height);
		return false;
	}

	LOG_INF("Setting render window size from {}x{} to {}x{}", m_width, m_height, width, height);

	m_width = width;
	m_height = height;
	m_texture_width = width;
	m_texture_height = height;
	m_hwnd = static_cast<HWND>(window_handle);
	m_is_rendering = true;

	// 清理现有资源
	Cleanup();

	// 初始化 Direct3D 设备和交换链
	if (!InitDeviceAndSwapChain()) {
		LOG_ERR("Failed to initialize Direct3D device and swap chain");
		return false;
	}

	// 初始化渲染目标视图
	if (!InitRenderTargetView()) {
		LOG_ERR("Failed to initialize render target view");
		return false;
	}

	// 初始化渲染管线（着色器、顶点缓冲区等）
	if (!InitRenderPipeline()) {
		LOG_ERR("Failed to initialize render pipeline");
		return false;
	}
	
	// 初始化纹理（用于接收视频帧数据）
	if (!InitTexture()) {
		LOG_ERR("Failed to initialize video texture");
		return false;
	}

	LOG_INF("Render window set successfully: {}x{}", m_width, m_height);

	return true;
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void D3DVideoRenderer::SetVideoTrack(rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track)
{
	std::lock_guard<std::mutex> lock(m_mutex);

	LOG_INF("Setting video track: {}", video_track ? video_track->id() : "nullptr");

	if (m_video_track) {
		m_video_track->RemoveSink(this);
		LOG_INF("Removed existing video track sink: {}", m_video_track->id());
	}

	m_video_track = video_track;

	if (video_track) {
		video_track->AddOrUpdateSink(this, rtc::VideoSinkWants());
		LOG_INF("Added video track sink: {}", video_track->id());
	}
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void D3DVideoRenderer::OnPaint()
{
	LOG_INF("OnPaint called, rendering lastest frame");

	if (!m_executor) {
		LOG_ERR("IMainThreadExecutor is null, cannot post render task");
		return;
	}

	m_executor->PostToMainThread([this]() {
		std::lock_guard<std::mutex> lock(m_mutex);
		DoRenderFrame(nullptr, m_texture_width, m_texture_height);
	});
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void D3DVideoRenderer::OnWindowSizeChanged()
{
	LOG_INF("OnWindowSizeChanged called, updating window size");

	if (!m_executor) {
		LOG_ERR("IMainThreadExecutor is null, cannot post update task");
		return;
	}

	std::lock_guard<std::mutex> lock(m_mutex);
	UpdateWindowSize();
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void D3DVideoRenderer::DoRenderFrame(const uint8_t* bgra_data, int width, int height)
{
	LOG_DBG("RenderFrame called: bgra_data={}, width={}, height={}", bgra_data, width, height);

	if (!m_is_rendering) {
		LOG_INF("Renderer is not rendering, skipping frame");
		return;
	}

	if (!m_swap_chain || !m_context || !m_render_target_view) {
		LOG_INF("Renderer not initialized, skipping render");
		return;
	}

	// 更新窗口大小
	RECT rc;
	if (GetClientRect(m_hwnd, &rc)) {
		int new_width = rc.right - rc.left;
		int new_height = rc.bottom - rc.top;
		if (new_width > 0 && new_height > 0 && (new_width != m_width || new_height != m_height)) {
			LOG_INF("Window size changed: {}x{} -> {}x{}", m_width, m_height, new_width, new_height);
			m_width = new_width;
			m_height = new_height;
			m_render_target_view.Reset();

			HRESULT hr = m_swap_chain->ResizeBuffers(0, m_width, m_height, DXGI_FORMAT_B8G8R8A8_UNORM, 0);
			if (FAILED(hr)) {
				LOG_ERR("ResizeBuffers failed: {}", hr);
				return;
			}

			if (!InitRenderTargetView()) {
				LOG_ERR("Failed to recreate render target view after resize");
				return;
			}
		}
	}

	// 更新纹理
	if (bgra_data) {
		UpdateTexture(bgra_data, width, height);
	} else if (m_bgra_buffer.empty()) {
		LOG_INF("No frame data available");
		return;
	} else {
		UpdateTexture(m_bgra_buffer.data(), m_texture_width, m_texture_height);
	}

	float window_aspect = (float)m_width / m_height;
	float frame_aspect = (float)m_texture_width / m_texture_height;
	float vp_width = (float)m_width;
	float vp_height = (float)m_height;
	if (window_aspect > frame_aspect) {
		vp_width = m_height * frame_aspect;
	}
	else {
		vp_height = m_width / frame_aspect;
	}
	float vp_x = (m_width - vp_width) / 2.0f;
	float vp_y = (m_height - vp_height) / 2.0f;

	LOG_DBG("Rendering frame: window size={}x{}, texture size={}x{}, viewport={}x{} at ({}, {})",
			m_width, m_height, m_texture_width, m_texture_height, vp_width, vp_height, vp_x, vp_y);

	// 设置渲染目标和视口
	m_context->OMSetRenderTargets(1, m_render_target_view.GetAddressOf(), nullptr);
	D3D11_VIEWPORT viewport = { vp_x, vp_y, (float)vp_width, (float)vp_height, 0.0f, 1.0f };
	m_context->RSSetViewports(1, &viewport);

	// 清屏
	float clear_color[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
	m_context->ClearRenderTargetView(m_render_target_view.Get(), clear_color);

	// 设置渲染管线
	m_context->IASetInputLayout(m_input_layout.Get());
	m_context->IASetVertexBuffers(0, 1, m_vertex_buffer.GetAddressOf(), &m_vertex_stride, &m_vertex_offset);
	m_context->IASetIndexBuffer(m_index_buffer.Get(), DXGI_FORMAT_R32_UINT, 0);
	m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
	m_context->VSSetShader(m_vertex_shader.Get(), nullptr, 0);
	m_context->PSSetShader(m_pixel_shader.Get(), nullptr, 0);
	m_context->PSSetShaderResources(0, 1, m_shader_resource_view.GetAddressOf());
	m_context->PSSetSamplers(0, 1, m_sampler_state.GetAddressOf());

	// 绘制全屏四边形
	m_context->DrawIndexed(6, 0, 0);

	Present(true);
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void D3DVideoRenderer::RenderFrame(const std::vector<uint8_t>& buf, int width, int height)
{
	std::lock_guard<std::mutex> lock(m_mutex);
	m_bgra_buffer = std::move(buf);
	DoRenderFrame(m_bgra_buffer.data(), width, height);
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void D3DVideoRenderer::OnFrame(const webrtc::VideoFrame& frame)
{
	LOG_DBG("Received video frame: id={}, size={}x{}, rotation={}",
			frame.id(), frame.width(), frame.height(), frame.rotation());

	if (!m_executor) {
		LOG_ERR("IMainThreadExecutor is null, cannot post render task");
		return;
	}

	// 获取视频帧的 I420 缓冲区
	rtc::scoped_refptr<webrtc::I420BufferInterface> buffer = frame.video_frame_buffer()->ToI420();
	if (!buffer) {
		LOG_ERR("Failed to get I420 buffer from video frame");
		return;
	}

	int width = buffer->width();
	int height = buffer->height();
	std::vector<uint8_t> bgra_buffer(width * height * 4);

	// 将 I420 转换为 BGRA
	int result = libyuv::I420ToARGB(
		buffer->DataY(), buffer->StrideY(),
		buffer->DataU(), buffer->StrideU(),
		buffer->DataV(), buffer->StrideV(),
		bgra_buffer.data(), width * 4,
		width, height
	);
	if (result != 0) {
		LOG_ERR("I420ToARGB conversion failed: {}", result);
		return;
	}

	std::weak_ptr<D3DVideoRenderer> self_wptr = shared_from_this();
	m_executor->PostToMainThread([self_wptr, bgra_buffer=std::move(bgra_buffer), width, height]() {
		if (auto self_sptr = self_wptr.lock()) {
			self_sptr->RenderFrame(bgra_buffer, width, height);
		}
	});
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void D3DVideoRenderer::Start()
{
	std::lock_guard<std::mutex> lock(m_mutex);
	m_is_rendering = true;
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void D3DVideoRenderer::Stop()
{
	std::lock_guard<std::mutex> lock(m_mutex);
	m_is_rendering = false;
}

//--------------------------------------------------------------------------------------------------
// 
//--------------------------------------------------------------------------------------------------
void D3DVideoRenderer::UpdateWindowSize()
{
	LOG_INF("Updating window size");

	RECT rc;
	if (!GetClientRect(m_hwnd, &rc)) {
		LOG_ERR("GetClientRect failed");
		return;
	}
	
	int width = rc.right - rc.left;
	int height = rc.bottom - rc.top;

	if (width <= 0 || height <= 0) {
		LOG_ERR("Invalid window size: {}x{}", width, height);
		return;
	}

	if (m_width == width && m_height == height) {
		LOG_ERR("Window size unchanged: {}x{}, no update needed", width, height);
		return;
	}

	m_width = width;
	m_height = height;
	m_render_target_view.Reset();

	HRESULT hr = m_swap_chain->ResizeBuffers(0, width, height, DXGI_FORMAT_B8G8R8A8_UNORM, 0);
	if (FAILED(hr)) {
		LOG_ERR("ResizeBuffers failed: {}", hr);
		return;
	}

	if (!InitRenderTargetView()) {
		LOG_ERR("Failed to recreate render target view after resize");
	}

	LOG_INF("Window resized: {}x{}", width, height);
}

////////////////////////////////////////////////////////////////////////////////////////////////////

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void D3DVideoRenderer::Cleanup() 
{
	LOG_INF("Cleaning up D3DVideoRenderer resources");

	m_shader_resource_view.Reset();
	m_video_texture.Reset();
	m_sampler_state.Reset();
	m_pixel_shader.Reset();
	m_vertex_shader.Reset();
	m_input_layout.Reset();
	m_index_buffer.Reset();
	m_vertex_buffer.Reset();
	m_render_target_view.Reset();
	m_swap_chain.Reset();
	m_context.Reset();
	m_device.Reset();
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
bool D3DVideoRenderer::InitDeviceAndSwapChain()
{
	DXGI_SWAP_CHAIN_DESC sd = {};
	sd.BufferCount = 2; // 双缓冲
	sd.BufferDesc.Width = m_width;
	sd.BufferDesc.Height = m_height;
	sd.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
	sd.BufferDesc.RefreshRate.Numerator = 60;
	sd.BufferDesc.RefreshRate.Denominator = 1;
	sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
	sd.OutputWindow = m_hwnd;
	sd.SampleDesc.Count = 1;
	sd.Windowed = TRUE;
	sd.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
	sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;

	UINT createDeviceFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
#ifdef _DEBUG
	createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif

	D3D_FEATURE_LEVEL feature_levels[] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_0, D3D_FEATURE_LEVEL_9_1 };
	D3D_FEATURE_LEVEL feature_level;
	HRESULT hr = D3D11CreateDeviceAndSwapChain(
		nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, createDeviceFlags,
		feature_levels, _countof(feature_levels), D3D11_SDK_VERSION,
		&sd, &m_swap_chain, &m_device, &feature_level, &m_context
	);

	if (FAILED(hr)) {
		LOG_ERR("D3D11CreateDeviceAndSwapChain failed: 0x%08X", hr);
		return false;
	}

	if (feature_level < D3D_FEATURE_LEVEL_9_1) {
		LOG_ERR("Unsupported feature level: 0x%04X", feature_level);
		return false;
	}

	return true;
}

//--------------------------------------------------------------------------------------------------
// 初始化渲染目标视图
//--------------------------------------------------------------------------------------------------
bool D3DVideoRenderer::InitRenderTargetView() 
{
	ComPtr<ID3D11Texture2D> back_buffer;
	HRESULT hr = m_swap_chain->GetBuffer(0, IID_PPV_ARGS(&back_buffer));
	if (FAILED(hr)) {
		LOG_ERR("GetBuffer failed: 0x%08X", hr);
		return false;
	}

	hr = m_device->CreateRenderTargetView(back_buffer.Get(), nullptr, &m_render_target_view);
	if (FAILED(hr)) {
		LOG_ERR("CreateRenderTargetView failed: 0x%08X", hr);
		return false;
	}

	return true;
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
bool D3DVideoRenderer::InitRenderPipeline()
{
	// 定义顶点结构
	struct Vertex {
		float position[3];
		float texcoord[2];
	};

	// 全屏四边形的顶点数据（两个三角形）
	Vertex vertices[] = {
		{ { -1.0f,  1.0f, 0.0f }, { 0.0f, 0.0f } }, // 左上
		{ {  1.0f,  1.0f, 0.0f }, { 1.0f, 0.0f } }, // 右上
		{ { -1.0f, -1.0f, 0.0f }, { 0.0f, 1.0f } }, // 左下
		{ {  1.0f, -1.0f, 0.0f }, { 1.0f, 1.0f } }  // 右下
	};
	uint32_t indices[] = { 0, 1, 2, 1, 3, 2 };

	// 创建顶点缓冲区
	D3D11_BUFFER_DESC vb_desc = {};
	vb_desc.ByteWidth = sizeof(vertices);
	vb_desc.Usage = D3D11_USAGE_IMMUTABLE;
	vb_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	D3D11_SUBRESOURCE_DATA vb_data = { vertices, 0, 0 };
	HRESULT hr = m_device->CreateBuffer(&vb_desc, &vb_data, &m_vertex_buffer);
	if (FAILED(hr)) {
		LOG_ERR("CreateVertexBuffer failed: 0x%08X", hr);
		return false;
	}

	// 创建索引缓冲区
	D3D11_BUFFER_DESC ib_desc = {};
	ib_desc.ByteWidth = sizeof(indices);
	ib_desc.Usage = D3D11_USAGE_IMMUTABLE;
	ib_desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
	D3D11_SUBRESOURCE_DATA ib_data = { indices, 0, 0 };
	hr = m_device->CreateBuffer(&ib_desc, &ib_data, &m_index_buffer);
	if (FAILED(hr)) {
		LOG_ERR("CreateIndexBuffer failed: 0x%08X", hr);
		return false;
	}

	// 编译顶点着色器
	ComPtr<ID3DBlob> vs_blob;
	hr = D3DCompile(
		vs_code, strlen(vs_code), nullptr, nullptr, nullptr,
		"VSMain", "vs_4_0", 0, 0, &vs_blob, nullptr
	);
	if (FAILED(hr)) {
		LOG_ERR("Compile vertex shader failed: 0x%08X", hr);
		return false;
	}

	hr = m_device->CreateVertexShader(
		vs_blob->GetBufferPointer(), 
		vs_blob->GetBufferSize(), 
		nullptr, 
		&m_vertex_shader);
	if (FAILED(hr)) {
		LOG_ERR("CreateVertexShader failed: 0x%08X", hr);
		return false;
	}

	// 定义输入布局
	D3D11_INPUT_ELEMENT_DESC layout[] = {
		{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }
	};
	hr = m_device->CreateInputLayout(
		layout, 
		_countof(layout), 
		vs_blob->GetBufferPointer(), 
		vs_blob->GetBufferSize(), 
		&m_input_layout);
	if (FAILED(hr)) {
		LOG_ERR("CreateInputLayout failed: 0x%08X", hr);
		return false;
	}

	// 编译像素着色器
	ComPtr<ID3DBlob> ps_blob;
	hr = D3DCompile(
		ps_code, strlen(ps_code), nullptr, nullptr, nullptr,
		"PSMain", "ps_4_0", 0, 0, &ps_blob, nullptr
	);
	if (FAILED(hr)) {
		LOG_ERR("Compile pixel shader failed: 0x%08X", hr);
		return false;
	}

	hr = m_device->CreatePixelShader(
		ps_blob->GetBufferPointer(), 
		ps_blob->GetBufferSize(), 
		nullptr, 
		&m_pixel_shader);
	if (FAILED(hr)) {
		LOG_ERR("CreatePixelShader failed: 0x%08X", hr);
		return false;
	}

	// 创建采样器
	D3D11_SAMPLER_DESC sampler_desc = {};
	sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
	sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
	sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
	sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
	sampler_desc.ComparisonFunc = D3D11_COMPARISON_NEVER;
	sampler_desc.MinLOD = 0;
	sampler_desc.MaxLOD = D3D11_FLOAT32_MAX;
	hr = m_device->CreateSamplerState(&sampler_desc, &m_sampler_state);
	if (FAILED(hr)) {
		LOG_ERR("CreateSamplerState failed: 0x%08X", hr);
		return false;
	}

	return true;
}

//--------------------------------------------------------------------------------------------------
// 初始化视频纹理
//--------------------------------------------------------------------------------------------------
bool D3DVideoRenderer::InitTexture()
{
	m_video_texture.Reset();
	m_shader_resource_view.Reset();

	D3D11_TEXTURE2D_DESC desc = {};
	desc.Width = m_texture_width;
	desc.Height = m_texture_height;
	desc.MipLevels = 1;
	desc.ArraySize = 1;
	desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
	desc.SampleDesc.Count = 1;
	desc.Usage = D3D11_USAGE_DYNAMIC;
	desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
	desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;

	HRESULT hr = m_device->CreateTexture2D(&desc, nullptr, &m_video_texture);
	if (FAILED(hr)) {
		LOG_ERR("CreateTexture2D failed: 0x%08X", hr);
		return false;
	}

	D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc = {};
	srv_desc.Format = desc.Format;
	srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
	srv_desc.Texture2D.MipLevels = 1;
	hr = m_device->CreateShaderResourceView(
		m_video_texture.Get(), 
		&srv_desc, 
		&m_shader_resource_view);
	if (FAILED(hr)) {
		LOG_ERR("CreateShaderResourceView failed: 0x%08X", hr);
		return false;
	}

	LOG_INF("Video texture initialized: {}x{}", m_texture_width, m_texture_height);

	return true;
}

//--------------------------------------------------------------------------------------------------
// 更新纹理数据（BGRA 格式）
//--------------------------------------------------------------------------------------------------
void D3DVideoRenderer::UpdateTexture(const uint8_t* bgra_data, int width, int height)
{
	// 如果纹理尺寸不匹配，重新创建纹理
	if (!m_video_texture || m_texture_width != width || m_texture_height != height) {
		m_texture_width = width;
		m_texture_height = height;
		if (!InitTexture()) {
			LOG_ERR("Failed to recreate texture");
			return;
		}
	}

	// 映射纹理并上传数据
	D3D11_MAPPED_SUBRESOURCE mapped;
	HRESULT hr = m_context->Map(m_video_texture.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped);
	if (FAILED(hr)) {
		LOG_ERR("Map texture failed: {}", hr);
		return;
	}

	// 考虑 RowPitch 对齐，逐行复制数据
	for (int y = 0; y < height; ++y) {
		memcpy(static_cast<uint8_t*>(mapped.pData) + y * mapped.RowPitch,
			bgra_data + y * width * 4, width * 4);
	}
	m_context->Unmap(m_video_texture.Get(), 0);
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void D3DVideoRenderer::HandleDeviceLost() 
{
	LOG_ERR("Device lost, attempting to recreate resources");
	// TODO:
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void D3DVideoRenderer::Present(bool vsync)
{
	if (m_swap_chain) {
		HRESULT hr = m_swap_chain->Present(vsync ? 1 : 0, 0);
		if (FAILED(hr)) {
			LOG_ERR("Failed to present swap chain: {}", hr);
			if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
				HandleDeviceLost();
			}
		}
	}
}

} // namespace p2pms